package com.example.shirotest.study;

import java.util.Arrays;

//堆排序
public class HeapSort {

    public static void main(String[] args) {
        //待排序 =》 升序
        int arr[] = {4,6,8,5,9};

        heapSort(arr);
    }

    //编写一个堆排序的方法
    public static void heapSort(int arr[]){
        System.out.println("HeapSort !!");

        //将无序序列构建成一个堆，根据升序降序需要选择大顶堆或小顶堆
        for (int i = arr.length/2 - 1; i >=0 ; i--) {
            adjustHeap(arr,i,arr.length);
        }

        //System.out.println("the arr : " + Arrays.toString(arr));

        //2)将堆顶元素与末尾元素交换，将最大元素“沉”到数组末端；
        //3)重新调整结构，使其满足堆定义，然后继续交换堆顶元素与当前末尾元素，反复执行调整+交换步骤，直到整个序列有序
        int temp;
        for (int i = arr.length-1; i > 0 ; i--) {
            //交换
            temp = arr[i];
            arr[i] = arr[0];
            arr[0] = temp;
            //调整
            adjustHeap(arr,0,i);
        }

        System.out.println("the arr : " + Arrays.toString(arr));
    }

    /**
     * 将一个数组（二叉树），调整成一个大顶堆
     * 功能：完成将以i对应的非叶子节点的树调整成大顶堆
     * 举例
     * 第1次 int arr[] = {4,6,8,5,9}; => i = 1 => adjustHeap => 得到 {4,9,8,5,6} 局部调整
     * 第2次 int arr[] = {4,9,8,5,6}; => i = 0 => adjustHeap => 得到 {9,6,8,5,4} 成为一个大顶堆
     * @param arr  待调整的数组
     * @param i    表示非叶子节点在数组中的索引
     * @param length 表示对多少个元素进行调整，length是逐渐的减少
     */
    public static void adjustHeap(int arr[],int i,int length){
        int temp = arr[i]; //先取出当前元素的值，保存到临时变量
        //开始调整
        //1. k = i * 2 + 1 ， k 是 i 节点的左子节点
        for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
            //说明左子节点的值小于右子节点的值
            if(k+1 < length && arr[k] < arr[k+1]){
                k++; //k 指向右子节点，大数字
            }
            if(arr[k] > temp){  //如果子节点大于父节点
                arr[i] = arr[k]; //把较大的值赋值给当前节点（顶节点）
                i = k;  //!!! i 指向 k,继续循环比较
            }else {
                break;
            }
        }
        //当for 循环结束后，我们已经将以 i 为父节点的树的最大值，放到了最顶（局部）
        arr[i] = temp; //将temp值放到调整后的位置

    }

}
